/*
 * Copyright 2008 Jens Meiss
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package hmvc.j2me.controller;

import java.util.Enumeration;
import java.util.Vector;

import hmvc.j2me.events.IEvent;
import hmvc.j2me.events.TerminateEvent;

/**
 * This is the basic IController implementation. Use this Class to create your
 * own Controller-Implementations
 * 
 * @author jens.meiss
 */
public abstract class AController implements IController {

	private Vector vectorListeningEvents;

	private IController controllerParent;

	private Vector vectorChildController;

	private Vector vectorTerminatedChilds;

	public void fireEventDown(IEvent event) {

		if (getVectorChildController() != null) {

			Enumeration enumeration = getVectorChildController().elements();

			/*
			 * send the Event to all child Controller
			 */
			while (enumeration.hasMoreElements()) {
				IController controller = (IController) enumeration
						.nextElement();
				controller.fireEvent(event, false, true, true);
			}
		}

	}

	public void addChildController(IController controller) {

		controller.setControllerParent(this);

		if (getVectorChildController() == null) {
			setVectorChildController(new Vector(5));
		}

		getVectorChildController().addElement(controller);
		
		controller.init();

	}

	public void fireEventUp(IEvent event) {

		/*
		 * send the Event to all parent Controller
		 */
		if (getControllerParent() != null) {
			getControllerParent().fireEvent(event, true, true, false);
		}

	}

	public void fireEvent(IEvent event, boolean up, boolean local, boolean down) {

		if (event == null) {
			throw new NullPointerException("The givent Event can't be null");
		}

		if (down) {
			fireEventDown(event);
		}

		if (local) {
			receiveEventLocal(event);
		}

		if (up) {
			fireEventUp(event);
		}

	}

	private void receiveEventLocal(IEvent event) {

		/*
		 * Aufräumen
		 */
		removeTerminatedChildController();

		/*
		 * Soll der Controller terminiert werden?
		 */
		if (event.getClass() == TerminateEvent.class) {

			/*
			 * terminate der Implementierung aufrufen
			 */
			terminate();

			/*
			 * Terminerten Controller beim parentController registrieren
			 */
			if (getControllerParent() != null) {
				getControllerParent().addTerminatedChildController(this);
			}
		}

		/*
		 * Hat sich der Controller für dieses Event registriert
		 */
		if (getVectorListeningEvents() != null) {
			if (getVectorListeningEvents().contains(event.getClass())) {
				receiveEvent(event);
			}
		}

	}

	private void removeTerminatedChildController() {

		if ((getVectorTerminatedChilds() == null)
				|| (getVectorTerminatedChilds().size() == 0)) {
			return;
		}

		Enumeration enumeration = getVectorTerminatedChilds().elements();

		while (enumeration.hasMoreElements()) {
			IController component = (IController) enumeration.nextElement();
			getVectorChildController().removeElement(component);
		}

		vectorTerminatedChilds.removeAllElements();
	}

	public void addTerminatedChildController(IController controller) {

		if (getVectorTerminatedChilds() == null) {
			setVectorTerminatedChilds(new Vector(5));
		}

		getVectorTerminatedChilds().addElement(controller);
	}

	private IController getControllerParent() {
		return controllerParent;
	}

	private Vector getVectorChildController() {
		return vectorChildController;
	}

	private Vector getVectorListeningEvents() {
		return vectorListeningEvents;
	}

	private Vector getVectorTerminatedChilds() {
		return vectorTerminatedChilds;
	}

	public void register(Class classOfEvent) {

		if (getVectorListeningEvents() == null) {
			setVectorListeningEvents(new Vector(5));
		}

		getVectorListeningEvents().addElement(classOfEvent);
	}

	public void setControllerParent(IController controllerParent) {

		if (getControllerParent() != null) {
			throw new NullPointerException("Can't overwriter partenController");
		}

		this.controllerParent = controllerParent;
	}

	private void setVectorChildController(Vector vectorChildController) {
		this.vectorChildController = vectorChildController;
	}

	private void setVectorListeningEvents(Vector vectorListeningEvents) {
		this.vectorListeningEvents = vectorListeningEvents;
	}

	private void setVectorTerminatedChilds(Vector vectorTerminatedChilds) {
		this.vectorTerminatedChilds = vectorTerminatedChilds;
	}
	
	public boolean containsChildController(Class classOfController) {
		
		if (getVectorChildController() != null) {
			
			Enumeration enumeration = getVectorChildController().elements();
			while (enumeration.hasMoreElements()) {
				IController controller = (IController) enumeration.nextElement();
				
				if (classOfController == controller.getClass()) {
					return true;
				}
			}
			
		}
		
		return false;
	}
}
